package com.sxau.software_educational_system_backend.utils;

import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.model.*;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.exceptions.ServerException;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.sts.model.v20150401.AssumeRoleRequest;
import com.aliyuncs.sts.model.v20150401.AssumeRoleResponse;
import com.sxau.software_educational_system_backend.domain.res.OssCredentialVO;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import com.aliyuncs.http.MethodType;

import org.springframework.boot.context.properties.ConfigurationProperties;

import java.io.ByteArrayInputStream;
import java.text.SimpleDateFormat;
import java.util.*;

@Data
@AllArgsConstructor
@Slf4j
public class AliOssUtil {

    private String endpoint;
    private String accessKeyId;
    private String accessKeySecret;
    private String bucketName;
    private String stsRegionId;
    private String roleArn;
    private Long durationSeconds;



    /**
     * 文件上传
     *
     * @param bytes
     * @param objectName
     * @return
     */
    public String upload(byte[] bytes, String objectName) {

        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

        try {
            // 创建PutObject请求。
            PutObjectResult putObjectResult = ossClient.putObject(bucketName, objectName, new ByteArrayInputStream(bytes));
        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
        } catch (ClientException ce) {
            System.out.println("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            System.out.println("Error Message:" + ce.getMessage());
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }

        //文件访问路径规则 https://BucketName.Endpoint/ObjectName
        StringBuilder stringBuilder = new StringBuilder("https://");
        stringBuilder
                .append(bucketName)
                .append(".")
                .append(endpoint)
                .append("/")
                .append(objectName);

        log.info("文件上传到:{}", stringBuilder.toString());

        return stringBuilder.toString();
    }

    public List<OSSObjectSummary> listFiles() {
        OSS ossClient = null;
        List<OSSObjectSummary> objectSummaries = new ArrayList<>();
        try {
            // 创建 OSSClient 实例
            ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

            // 创建 ListObjectsRequest 对象
            ListObjectsRequest listRequest = new ListObjectsRequest(bucketName);

            String nextMarker = null;

            // 分页获取文件列表
            do {
                if (nextMarker != null) {
                    listRequest.setMarker(nextMarker);
                }

                // 执行请求获取文件列表
                ObjectListing objectListing = ossClient.listObjects(listRequest);

                //获取文件信息
                objectSummaries = objectListing.getObjectSummaries();

                // 获取下一页标记
                nextMarker = objectListing.getNextMarker();

            } while (nextMarker != null);

        } catch (Exception e) {
            System.err.println("获取 OSS 文件列表失败: " + e.getMessage());
            e.printStackTrace();
        } finally {
            // 关闭 OSSClient
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }

        return objectSummaries;
    }

    /**
     * 删除单个 OSS 文件
     * @param objectKey 文件路径（键）
     * @return 删除成功返回 true，失败返回 false
     */
    public boolean deleteFile(String objectKey) {
        OSS ossClient = null;
        try {
            // 创建 OSSClient 实例
            ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

            // 检查文件是否存在
            boolean exists = ossClient.doesObjectExist(bucketName, objectKey);
            if (!exists) {
                System.out.println("文件不存在: " + objectKey);
                return false;
            }

            // 删除文件
            ossClient.deleteObject(bucketName, objectKey);
            System.out.println("文件删除成功: " + objectKey);
            return true;

        } catch (Exception e) {
            System.err.println("删除文件失败: " + e.getMessage());
            e.printStackTrace();
            return false;
        } finally {
            // 关闭 OSSClient
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }

    /**
     * 批量删除多个 OSS 文件

     * @param objectKeys 文件路径列表
     * @return 删除成功的文件列表
     */
    public List<String> deleteFiles(List<String> objectKeys) {
        OSS ossClient = null;
        try {
            // 创建 OSSClient 实例
            ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

            // 执行批量删除
            DeleteObjectsRequest deleteRequest = new DeleteObjectsRequest(bucketName)
                    .withKeys(objectKeys);
            DeleteObjectsResult deleteResult = ossClient.deleteObjects(deleteRequest);

            List<String> deletedObjects = deleteResult.getDeletedObjects();
            System.out.printf("成功删除 %d 个文件%n", deletedObjects.size());
            return deletedObjects;

        } catch (Exception e) {
            System.err.println("批量删除文件失败: " + e.getMessage());
            e.printStackTrace();
            return Arrays.asList();
        } finally {
            // 关闭 OSSClient
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }


    /**
     * 获取 OSS 临时访问凭证
     */
    public OssCredentialVO getOssTemporaryCredential() {
        try {
            DefaultProfile profile = DefaultProfile.getProfile(
                    stsRegionId,
                    accessKeyId,
                    accessKeySecret
            );
            System.out.println("STS 获取临时访问凭证开始");
            System.out.println(profile);
            IAcsClient client = new DefaultAcsClient(profile);

            AssumeRoleRequest request = new AssumeRoleRequest();
            request.setMethod(MethodType.POST);
            request.setRoleArn(roleArn);
            request.setRoleSessionName("oss-session-sehome"); // 动态会话名

            if (durationSeconds != null) {
                request.setDurationSeconds(durationSeconds);
            }

            AssumeRoleResponse response = client.getAcsResponse(request);

            // 转换ISO 8601时间到Unix时间戳
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
            sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
            Date expirationDate = sdf.parse(response.getCredentials().getExpiration());
            long expirationTimestamp = expirationDate.getTime() / 1000;

            OssCredentialVO credential = new OssCredentialVO();
            credential.setAccessKeyId(response.getCredentials().getAccessKeyId());
            credential.setAccessKeySecret(response.getCredentials().getAccessKeySecret());
            credential.setSecurityToken(response.getCredentials().getSecurityToken());
            credential.setExpiresIn((int) expirationTimestamp); // 秒级时间戳

            return credential;

        } catch (ClientException | ServerException e) {
            log.error("获取OSS临时凭证失败", e);
            throw new RuntimeException("STS服务错误: " , e);
        } catch (Exception e) { // 捕获其他异常（如日期解析异常）
            log.error("系统异常", e);
            throw new RuntimeException("系统内部错误");
        }
    }
}
